home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_usrdoc / SVGALIB-.{2E / LRMI-0.5M / LRMI.C < prev    next >
C/C++ Source or Header  |  1999-09-17  |  17KB  |  884 lines

  1. /*
  2. Linux Real Mode Interface - A library of DPMI-like functions for Linux.
  3.  
  4. Copyright (C) 1998 by Josh Vanderhoof
  5.  
  6. You are free to distribute and modify this file, as long as you
  7. do not remove this copyright notice and clearly label modified
  8. versions as being modified.
  9.  
  10. This software has NO WARRANTY.  Use it at your own risk.
  11. */
  12.  
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <asm/vm86.h>
  16.  
  17. #ifdef USE_LIBC_VM86
  18. #include <sys/vm86.h>
  19. #endif
  20.  
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <sys/mman.h>
  24. #include <unistd.h>
  25. #include <fcntl.h>
  26.  
  27. #include "lrmi.h"
  28.  
  29. #define REAL_MEM_BASE     ((void *)0x10000)
  30. #define REAL_MEM_SIZE     0x10000
  31. #define REAL_MEM_BLOCKS     0x100
  32.  
  33. struct mem_block
  34.     {
  35.     unsigned int size : 20;
  36.     unsigned int free : 1;
  37.     };
  38.  
  39. static struct
  40.     {
  41.     int ready;
  42.     int count;
  43.     struct mem_block blocks[REAL_MEM_BLOCKS];
  44.     } mem_info = { 0 };
  45.  
  46. static int
  47. real_mem_init(void)
  48.     {
  49.     void *m;
  50.     int fd_zero;
  51.  
  52.     if (mem_info.ready)
  53.         return 1;
  54.  
  55.     fd_zero = open("/dev/zero", O_RDONLY);
  56.     if (fd_zero == -1)
  57.         {
  58.         perror("open /dev/zero");
  59.         return 0;
  60.         }
  61.  
  62.     m = mmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE,
  63.      PROT_READ | PROT_WRITE | PROT_EXEC,
  64.      MAP_FIXED | MAP_PRIVATE, fd_zero, 0);
  65.  
  66.     if (m == (void *)-1)
  67.         {
  68.         perror("mmap /dev/zero");
  69.         close(fd_zero);
  70.         return 0;
  71.         }
  72.  
  73.     mem_info.ready = 1;
  74.     mem_info.count = 1;
  75.     mem_info.blocks[0].size = REAL_MEM_SIZE;
  76.     mem_info.blocks[0].free = 1;
  77.  
  78.     return 1;
  79.     }
  80.  
  81.  
  82. static void
  83. insert_block(int i)
  84.     {
  85.     memmove(
  86.      mem_info.blocks + i + 1,
  87.      mem_info.blocks + i,
  88.      (mem_info.count - i) * sizeof(struct mem_block));
  89.  
  90.     mem_info.count++;
  91.     }
  92.  
  93. static void
  94. delete_block(int i)
  95.     {
  96.     mem_info.count--;
  97.  
  98.     memmove(
  99.      mem_info.blocks + i,
  100.      mem_info.blocks + i + 1,
  101.      (mem_info.count - i) * sizeof(struct mem_block));
  102.     }
  103.  
  104. void *
  105. LRMI_alloc_real(int size)
  106.     {
  107.     int i;
  108.     char *r = (char *)REAL_MEM_BASE;
  109.  
  110.     if (!mem_info.ready)
  111.         return NULL;
  112.  
  113.     if (mem_info.count == REAL_MEM_BLOCKS)
  114.         return NULL;
  115.  
  116.     size = (size + 15) & ~15;
  117.  
  118.     for (i = 0; i < mem_info.count; i++)
  119.         {
  120.         if (mem_info.blocks[i].free && size < mem_info.blocks[i].size)
  121.             {
  122.             insert_block(i);
  123.  
  124.             mem_info.blocks[i].size = size;
  125.             mem_info.blocks[i].free = 0;
  126.             mem_info.blocks[i + 1].size -= size;
  127.  
  128.             return (void *)r;
  129.             }
  130.  
  131.         r += mem_info.blocks[i].size;
  132.         }
  133.  
  134.     return NULL;
  135.     }
  136.  
  137.  
  138. void
  139. LRMI_free_real(void *m)
  140.     {
  141.     int i;
  142.     char *r = (char *)REAL_MEM_BASE;
  143.  
  144.     if (!mem_info.ready)
  145.         return;
  146.  
  147.     i = 0;
  148.     while (m != (void *)r)
  149.         {
  150.         r += mem_info.blocks[i].size;
  151.         i++;
  152.         if (i == mem_info.count)
  153.             return;
  154.         }
  155.  
  156.     mem_info.blocks[i].free = 1;
  157.  
  158.     if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free)
  159.         {
  160.         mem_info.blocks[i].size += mem_info.blocks[i + 1].size;
  161.         delete_block(i + 1);
  162.         }
  163.  
  164.     if (i - 1 >= 0 && mem_info.blocks[i - 1].free)
  165.         {
  166.         mem_info.blocks[i - 1].size += mem_info.blocks[i].size;
  167.         delete_block(i);
  168.         }
  169.     }
  170.  
  171.  
  172. #define DEFAULT_VM86_FLAGS     (IF_MASK | IOPL_MASK)
  173. #define DEFAULT_STACK_SIZE     0x1000
  174. #define RETURN_TO_32_INT     255
  175.  
  176. static struct
  177.     {
  178.     int ready;
  179.     unsigned short ret_seg, ret_off;
  180.     unsigned short stack_seg, stack_off;
  181.     struct vm86_struct vm;
  182.     } context = { 0 };
  183.  
  184.  
  185. static inline void
  186. set_bit(unsigned int bit, void *array)
  187.     {
  188.     unsigned char *a = array;
  189.  
  190.     a[bit / 8] |= (1 << (bit % 8));
  191.     }
  192.  
  193.  
  194. static inline unsigned int
  195. get_int_seg(int i)
  196.     {
  197.     return *(unsigned short *)(i * 4 + 2);
  198.     }
  199.  
  200.  
  201. static inline unsigned int
  202. get_int_off(int i)
  203.     {
  204.     return *(unsigned short *)(i * 4);
  205.     }
  206.  
  207.  
  208. static inline void
  209. pushw(unsigned short i)
  210.     {
  211.     struct vm86_regs *r = &context.vm.regs;
  212.     r->esp -= 2;
  213.     *(unsigned short *)(((unsigned int)r->ss << 4) + r->esp) = i;
  214.     }
  215.  
  216.  
  217. int
  218. LRMI_init(void)
  219.     {
  220.     void *m;
  221.     int fd_mem;
  222.  
  223.     if (context.ready)
  224.         return 1;
  225.  
  226.     if (!real_mem_init())
  227.         return 0;
  228.  
  229.     /*
  230.      Map the Interrupt Vectors (0x0 - 0x400) + BIOS data (0x400 - 0x502)
  231.      and the ROM (0xa0000 - 0x100000)
  232.     */
  233.     fd_mem = open("/dev/mem", O_RDWR);
  234.  
  235.     if (fd_mem == -1)
  236.         {
  237.         perror("open /dev/mem");
  238.         return 0;
  239.         }
  240.  
  241.     m = mmap((void *)0, 0x502,
  242.      PROT_READ | PROT_WRITE | PROT_EXEC,
  243.      MAP_FIXED | MAP_PRIVATE, fd_mem, 0);
  244.  
  245.     if (m == (void *)-1)
  246.         {
  247.         perror("mmap /dev/mem");
  248.         return 0;
  249.         }
  250.  
  251.     m = mmap((void *)0xa0000, 0x100000 - 0xa0000,
  252.      PROT_READ | PROT_WRITE,
  253.      MAP_FIXED | MAP_SHARED, fd_mem, 0xa0000);
  254.  
  255.     if (m == (void *)-1)
  256.         {
  257.         perror("mmap /dev/mem");
  258.         return 0;
  259.         }
  260.  
  261.  
  262.     /*
  263.      Allocate a stack
  264.     */
  265.     m = LRMI_alloc_real(DEFAULT_STACK_SIZE);
  266.  
  267.     context.stack_seg = (unsigned int)m >> 4;
  268.     context.stack_off = DEFAULT_STACK_SIZE;
  269.  
  270.     /*
  271.      Allocate the return to 32 bit routine
  272.     */
  273.     m = LRMI_alloc_real(2);
  274.  
  275.     context.ret_seg = (unsigned int)m >> 4;
  276.     context.ret_off = (unsigned int)m & 0xf;
  277.  
  278.     ((unsigned char *)m)[0] = 0xcd;     /* int opcode */
  279.     ((unsigned char *)m)[1] = RETURN_TO_32_INT;
  280.  
  281.     memset(&context.vm, 0, sizeof(context.vm));
  282.  
  283.     /*
  284.      Enable kernel emulation of all ints except RETURN_TO_32_INT
  285.     */
  286.     memset(&context.vm.int_revectored, 0, sizeof(context.vm.int_revectored));
  287.     set_bit(RETURN_TO_32_INT, &context.vm.int_revectored);
  288.  
  289.     context.ready = 1;
  290.  
  291.     return 1;
  292.     }
  293.  
  294.  
  295. static void
  296. set_regs(struct LRMI_regs *r)
  297.     {
  298.     context.vm.regs.edi = r->edi;
  299.     context.vm.regs.esi = r->esi;
  300.     context.vm.regs.ebp = r->ebp;
  301.     context.vm.regs.ebx = r->ebx;
  302.     context.vm.regs.edx = r->edx;
  303.     context.vm.regs.ecx = r->ecx;
  304.     context.vm.regs.eax = r->eax;
  305.     context.vm.regs.eflags = DEFAULT_VM86_FLAGS;
  306.     context.vm.regs.es = r->es;
  307.     context.vm.regs.ds = r->ds;
  308.     context.vm.regs.fs = r->fs;
  309.     context.vm.regs.gs = r->gs;
  310.     }
  311.  
  312.  
  313. static void
  314. get_regs(struct LRMI_regs *r)
  315.     {
  316.     r->edi = context.vm.regs.edi;
  317.     r->esi = context.vm.regs.esi;
  318.     r->ebp = context.vm.regs.ebp;
  319.     r->ebx = context.vm.regs.ebx;
  320.     r->edx = context.vm.regs.edx;
  321.     r->ecx = context.vm.regs.ecx;
  322.     r->eax = context.vm.regs.eax;
  323.     r->flags = context.vm.regs.eflags;
  324.     r->es = context.vm.regs.es;
  325.     r->ds = context.vm.regs.ds;
  326.     r->fs = context.vm.regs.fs;
  327.     r->gs = context.vm.regs.gs;
  328.     }
  329.  
  330. #define DIRECTION_FLAG     (1 << 10)
  331.  
  332. static void
  333. em_ins(int size)
  334.     {
  335.     unsigned int edx, edi;
  336.  
  337.     edx = context.vm.regs.edx & 0xffff;
  338.     edi = context.vm.regs.edi & 0xffff;
  339.     edi += (unsigned int)context.vm.regs.ds << 4;
  340.  
  341.     if (context.vm.regs.eflags & DIRECTION_FLAG)
  342.         {
  343.         if (size == 4)
  344.             asm volatile ("std; insl; cld"
  345.              : "=D" (edi) : "d" (edx), "0" (edi));
  346.         else if (size == 2)
  347.             asm volatile ("std; insw; cld"
  348.              : "=D" (edi) : "d" (edx), "0" (edi));
  349.         else
  350.             asm volatile ("std; insb; cld"
  351.              : "=D" (edi) : "d" (edx), "0" (edi));
  352.         }
  353.     else
  354.         {
  355.         if (size == 4)
  356.             asm volatile ("cld; insl"
  357.              : "=D" (edi) : "d" (edx), "0" (edi));
  358.         else if (size == 2)
  359.             asm volatile ("cld; insw"
  360.              : "=D" (edi) : "d" (edx), "0" (edi));
  361.         else
  362.             asm volatile ("cld; insb"
  363.              : "=D" (edi) : "d" (edx), "0" (edi));
  364.         }
  365.  
  366.     edi -= (unsigned int)context.vm.regs.ds << 4;
  367.  
  368.     context.vm.regs.edi &= 0xffff0000;
  369.     context.vm.regs.edi |= edi & 0xffff;
  370.     }
  371.  
  372. static void
  373. em_rep_ins(int size)
  374.     {
  375.     unsigned int ecx, edx, edi;
  376.  
  377.     ecx = context.vm.regs.ecx & 0xffff;
  378.     edx = context.vm.regs.edx & 0xffff;
  379.     edi = context.vm.regs.edi & 0xffff;
  380.     edi += (unsigned int)context.vm.regs.ds << 4;
  381.  
  382.     if (context.vm.regs.eflags & DIRECTION_FLAG)
  383.         {
  384.         if (size == 4)
  385.             asm volatile ("std; rep; insl; cld"
  386.              : "=D" (edi), "=c" (ecx)
  387.              : "d" (edx), "0" (edi), "1" (ecx));
  388.         else if (size == 2)
  389.             asm volatile ("std; rep; insw; cld"
  390.              : "=D" (edi), "=c" (ecx)
  391.              : "d" (edx), "0" (edi), "1" (ecx));
  392.         else
  393.             asm volatile ("std; rep; insb; cld"
  394.              : "=D" (edi), "=c" (ecx)
  395.              : "d" (edx), "0" (edi), "1" (ecx));
  396.         }
  397.     else
  398.         {
  399.         if (size == 4)
  400.             asm volatile ("cld; rep; insl"
  401.              : "=D" (edi), "=c" (ecx)
  402.              : "d" (edx), "0" (edi), "1" (ecx));
  403.         else if (size == 2)
  404.             asm volatile ("cld; rep; insw"
  405.              : "=D" (edi), "=c" (ecx)
  406.              : "d" (edx), "0" (edi), "1" (ecx));
  407.         else
  408.             asm volatile ("cld; rep; insb"
  409.              : "=D" (edi), "=c" (ecx)
  410.              : "d" (edx), "0" (edi), "1" (ecx));
  411.         }
  412.  
  413.     edi -= (unsigned int)context.vm.regs.ds << 4;
  414.  
  415.     context.vm.regs.edi &= 0xffff0000;
  416.     context.vm.regs.edi |= edi & 0xffff;
  417.  
  418.     context.vm.regs.ecx &= 0xffff0000;
  419.     context.vm.regs.ecx |= ecx & 0xffff;
  420.     }
  421.  
  422. static void
  423. em_outs(int size)
  424.     {
  425.     unsigned int edx, esi;
  426.  
  427.     edx = context.vm.regs.edx & 0xffff;
  428.     esi = context.vm.regs.esi & 0xffff;
  429.     esi += (unsigned int)context.vm.regs.ds << 4;
  430.  
  431.     if (context.vm.regs.eflags & DIRECTION_FLAG)
  432.         {
  433.         if (size == 4)
  434.             asm volatile ("std; outsl; cld"
  435.              : "=S" (esi) : "d" (edx), "0" (esi));
  436.         else if (size == 2)
  437.             asm volatile ("std; outsw; cld"
  438.              : "=S" (esi) : "d" (edx), "0" (esi));
  439.         else
  440.             asm volatile ("std; outsb; cld"
  441.              : "=S" (esi) : "d" (edx), "0" (esi));
  442.         }
  443.     else
  444.         {
  445.         if (size == 4)
  446.             asm volatile ("cld; outsl"
  447.              : "=S" (esi) : "d" (edx), "0" (esi));
  448.         else if (size == 2)
  449.             asm volatile ("cld; outsw"
  450.              : "=S" (esi) : "d" (edx), "0" (esi));
  451.         else
  452.             asm volatile ("cld; outsb"
  453.              : "=S" (esi) : "d" (edx), "0" (esi));
  454.         }
  455.  
  456.     esi -= (unsigned int)context.vm.regs.ds << 4;
  457.  
  458.     context.vm.regs.esi &= 0xffff0000;
  459.     context.vm.regs.esi |= esi & 0xffff;
  460.     }
  461.  
  462. static void
  463. em_rep_outs(int size)
  464.     {
  465.     unsigned int ecx, edx, esi;
  466.  
  467.     ecx = context.vm.regs.ecx & 0xffff;
  468.     edx = context.vm.regs.edx & 0xffff;
  469.     esi = context.vm.regs.esi & 0xffff;
  470.     esi += (unsigned int)context.vm.regs.ds << 4;
  471.  
  472.     if (context.vm.regs.eflags & DIRECTION_FLAG)
  473.         {
  474.         if (size == 4)
  475.             asm volatile ("std; rep; outsl; cld"
  476.              : "=S" (esi), "=c" (ecx)
  477.              : "d" (edx), "0" (esi), "1" (ecx));
  478.         else if (size == 2)
  479.             asm volatile ("std; rep; outsw; cld"
  480.              : "=S" (esi), "=c" (ecx)
  481.              : "d" (edx), "0" (esi), "1" (ecx));
  482.         else
  483.             asm volatile ("std; rep; outsb; cld"
  484.              : "=S" (esi), "=c" (ecx)
  485.              : "d" (edx), "0" (esi), "1" (ecx));
  486.         }
  487.     else
  488.         {
  489.         if (size == 4)
  490.             asm volatile ("cld; rep; outsl"
  491.              : "=S" (esi), "=c" (ecx)
  492.              : "d" (edx), "0" (esi), "1" (ecx));
  493.         else if (size == 2)
  494.             asm volatile ("cld; rep; outsw"
  495.              : "=S" (esi), "=c" (ecx)
  496.              : "d" (edx), "0" (esi), "1" (ecx));
  497.         else
  498.             asm volatile ("cld; rep; outsb"
  499.              : "=S" (esi), "=c" (ecx)
  500.              : "d" (edx), "0" (esi), "1" (ecx));
  501.         }
  502.  
  503.     esi -= (unsigned int)context.vm.regs.ds << 4;
  504.  
  505.     context.vm.regs.esi &= 0xffff0000;
  506.     context.vm.regs.esi |= esi & 0xffff;
  507.  
  508.     context.vm.regs.ecx &= 0xffff0000;
  509.     context.vm.regs.ecx |= ecx & 0xffff;
  510.     }
  511.  
  512. static void
  513. em_inb(void)
  514.     {
  515.     asm volatile ("inb (%w1), %b0"
  516.      : "=a" (context.vm.regs.eax)
  517.      : "d" (context.vm.regs.edx), "0" (context.vm.regs.eax));
  518.     }
  519.  
  520. static void
  521. em_inw(void)
  522.     {
  523.     asm volatile ("inw (%w1), %w0"
  524.      : "=a" (context.vm.regs.eax)
  525.      : "d" (context.vm.regs.edx), "0" (context.vm.regs.eax));
  526.     }
  527.  
  528. static void
  529. em_inl(void)
  530.     {
  531.     asm volatile ("inl (%w1), %0"
  532.      : "=a" (context.vm.regs.eax)
  533.      : "d" (context.vm.regs.edx));
  534.     }
  535.  
  536. static void
  537. em_outb(void)
  538.     {
  539.     asm volatile ("outb %b0, (%w1)"
  540.      : : "a" (context.vm.regs.eax),
  541.      "d" (context.vm.regs.edx));
  542.     }
  543.  
  544. static void
  545. em_outw(void)
  546.     {
  547.     asm volatile ("outw %w0, (%w1)"
  548.      : : "a" (context.vm.regs.eax),
  549.      "d" (context.vm.regs.edx));
  550.     }
  551.  
  552. static void
  553. em_outl(void)
  554.     {
  555.     asm volatile ("outl %0, (%w1)"
  556.      : : "a" (context.vm.regs.eax),
  557.      "d" (context.vm.regs.edx));
  558.     }
  559.  
  560. static int
  561. emulate(void)
  562.     {
  563.     unsigned char *insn;
  564.     struct
  565.         {
  566.         unsigned int size : 1;
  567.         unsigned int rep : 1;
  568.         } prefix = { 0, 0 };
  569.     int i = 0;
  570.  
  571.     insn = (unsigned char *)((unsigned int)context.vm.regs.cs << 4);
  572.     insn += context.vm.regs.eip;
  573.  
  574.     while (1)
  575.         {
  576.         if (insn[i] == 0x66)
  577.             {
  578.             prefix.size = 1 - prefix.size;
  579.             i++;
  580.             }
  581.         else if (insn[i] == 0xf3)
  582.             {
  583.             prefix.rep = 1;
  584.             i++;
  585.             }
  586.         else if (insn[i] == 0xf0 || insn[i] == 0xf2
  587.          || insn[i] == 0x26 || insn[i] == 0x2e
  588.          || insn[i] == 0x36 || insn[i] == 0x3e
  589.          || insn[i] == 0x64 || insn[i] == 0x65
  590.          || insn[i] == 0x67)
  591.             {
  592.             /* these prefixes are just ignored */
  593.             i++;
  594.             }
  595.         else if (insn[i] == 0x6c)
  596.             {
  597.             if (prefix.rep)
  598.                 em_rep_ins(1);
  599.             else
  600.                 em_ins(1);
  601.             i++;
  602.             break;
  603.             }
  604.         else if (insn[i] == 0x6d)
  605.             {
  606.             if (prefix.rep)
  607.                 {
  608.                 if (prefix.size)
  609.                     em_rep_ins(4);
  610.                 else
  611.                     em_rep_ins(2);
  612.                 }
  613.             else
  614.                 {
  615.                 if (prefix.size)
  616.                     em_ins(4);
  617.                 else
  618.                     em_ins(2);
  619.                 }
  620.             i++;
  621.             break;
  622.             }
  623.         else if (insn[i] == 0x6e)
  624.             {
  625.             if (prefix.rep)
  626.                 em_rep_outs(1);
  627.             else
  628.                 em_outs(1);
  629.             i++;
  630.             break;
  631.             }
  632.         else if (insn[i] == 0x6f)
  633.             {
  634.             if (prefix.rep)
  635.                 {
  636.                 if (prefix.size)
  637.                     em_rep_outs(4);
  638.                 else
  639.                     em_rep_outs(2);
  640.                 }
  641.             else
  642.                 {
  643.                 if (prefix.size)
  644.                     em_outs(4);
  645.                 else
  646.                     em_outs(2);
  647.                 }
  648.             i++;
  649.             break;
  650.             }
  651.         else if (insn[i] == 0xec)
  652.             {
  653.             em_inb();
  654.             i++;
  655.             break;
  656.             }
  657.         else if (insn[i] == 0xed)
  658.             {
  659.             if (prefix.size)
  660.                 em_inl();
  661.             else
  662.                 em_inw();
  663.             i++;
  664.             break;
  665.             }
  666.         else if (insn[i] == 0xee)
  667.             {
  668.             em_outb();
  669.             i++;
  670.             break;
  671.             }
  672.         else if (insn[i] == 0xef)
  673.             {
  674.             if (prefix.size)
  675.                 em_outl();
  676.             else
  677.                 em_outw();
  678.  
  679.             i++;
  680.             break;
  681.             }
  682.         else
  683.             return 0;
  684.         }
  685.  
  686.     context.vm.regs.eip += i;
  687.     return 1;
  688.     }
  689.  
  690.  
  691. /*
  692.  I don't know how to make sure I get the right vm86() from libc.
  693.  The one I want is syscall # 113 (vm86old() in libc 5, vm86() in glibc)
  694.  which should be declared as "int vm86(struct vm86_struct *);" in
  695.  <sys/vm86.h>.
  696.  
  697.  This just does syscall 113 with inline asm, which should work
  698.  for both libc's (I hope).
  699. */
  700. #if !defined(USE_LIBC_VM86)
  701. static int
  702. lrmi_vm86(struct vm86_struct *vm)
  703.     {
  704.     int r;
  705. #ifdef __PIC__
  706.     asm volatile (
  707.      "pushl %%ebx\n\t"
  708.      "movl %2, %%ebx\n\t"
  709.      "int $0x80\n\t"
  710.      "popl %%ebx"
  711.      : "=a" (r)
  712.      : "0" (113), "r" (vm));
  713. #else
  714.     asm volatile (
  715.      "int $0x80"
  716.      : "=a" (r)
  717.      : "0" (113), "b" (vm));
  718. #endif
  719.     return r;
  720.     }
  721. #else
  722. #define lrmi_vm86 vm86
  723. #endif
  724.  
  725.  
  726. static void
  727. debug_info(int vret)
  728.     {
  729.     int i;
  730.     unsigned char *p;
  731.  
  732.     fputs("vm86() failed\n", stderr);
  733.     fprintf(stderr, "return = 0x%x\n", vret);
  734.     fprintf(stderr, "eax = 0x%08lx\n", context.vm.regs.eax);
  735.     fprintf(stderr, "ebx = 0x%08lx\n", context.vm.regs.ebx);
  736.     fprintf(stderr, "ecx = 0x%08lx\n", context.vm.regs.ecx);
  737.     fprintf(stderr, "edx = 0x%08lx\n", context.vm.regs.edx);
  738.     fprintf(stderr, "esi = 0x%08lx\n", context.vm.regs.esi);
  739.     fprintf(stderr, "edi = 0x%08lx\n", context.vm.regs.edi);
  740.     fprintf(stderr, "ebp = 0x%08lx\n", context.vm.regs.ebp);
  741.     fprintf(stderr, "eip = 0x%08lx\n", context.vm.regs.eip);
  742.     fprintf(stderr, "cs  = 0x%04x\n", context.vm.regs.cs);
  743.     fprintf(stderr, "esp = 0x%08lx\n", context.vm.regs.esp);
  744.     fprintf(stderr, "ss  = 0x%04x\n", context.vm.regs.ss);
  745.     fprintf(stderr, "ds  = 0x%04x\n", context.vm.regs.ds);
  746.     fprintf(stderr, "es  = 0x%04x\n", context.vm.regs.es);
  747.     fprintf(stderr, "fs  = 0x%04x\n", context.vm.regs.fs);
  748.     fprintf(stderr, "gs  = 0x%04x\n", context.vm.regs.gs);
  749.     fprintf(stderr, "eflags  = 0x%08lx\n", context.vm.regs.eflags);
  750.  
  751.     fputs("cs:ip = [ ", stderr);
  752.  
  753.     p = (unsigned char *)((context.vm.regs.cs << 4) + (context.vm.regs.eip & 0xffff));
  754.  
  755.     for (i = 0; i < 16; ++i)
  756.         fprintf(stderr, "%02x ", (unsigned int)p[i]);
  757.  
  758.     fputs("]\n", stderr);
  759.     }
  760.  
  761.  
  762. static int
  763. run_vm86(void)
  764.     {
  765.     unsigned int vret;
  766.  
  767.     while (1)
  768.         {
  769.         vret = lrmi_vm86(&context.vm);
  770.  
  771.         if (VM86_TYPE(vret) == VM86_INTx)
  772.             {
  773.             unsigned int v = VM86_ARG(vret);
  774.  
  775.             if (v == RETURN_TO_32_INT)
  776.                 return 1;
  777.  
  778.             pushw(context.vm.regs.eflags);
  779.             pushw(context.vm.regs.cs);
  780.             pushw(context.vm.regs.eip);
  781.  
  782.             context.vm.regs.cs = get_int_seg(v);
  783.             context.vm.regs.eip = get_int_off(v);
  784.             context.vm.regs.eflags &= ~(VIF_MASK | TF_MASK);
  785.  
  786.             continue;
  787.             }
  788.  
  789.         if (VM86_TYPE(vret) != VM86_UNKNOWN)
  790.             break;
  791.  
  792.         if (!emulate())
  793.             break;
  794.         }
  795.  
  796.     debug_info(vret);
  797.  
  798.     return 0;
  799.     }
  800.  
  801.  
  802. int
  803. LRMI_call(struct LRMI_regs *r)
  804.     {
  805.     unsigned int vret;
  806.  
  807.     memset(&context.vm.regs, 0, sizeof(context.vm.regs));
  808.  
  809.     set_regs(r);
  810.  
  811.     context.vm.regs.cs = r->cs;
  812.     context.vm.regs.eip = r->ip;
  813.  
  814.     if (r->ss == 0 && r->sp == 0)
  815.         {
  816.         context.vm.regs.ss = context.stack_seg;
  817.         context.vm.regs.esp = context.stack_off;
  818.         }
  819.     else
  820.         {
  821.         context.vm.regs.ss = r->ss;
  822.         context.vm.regs.esp = r->sp;
  823.         }
  824.  
  825.     pushw(context.ret_seg);
  826.     pushw(context.ret_off);
  827.  
  828.     vret = run_vm86();
  829.  
  830.     get_regs(r);
  831.  
  832.     return vret;
  833.     }
  834.  
  835.  
  836. int
  837. LRMI_int(int i, struct LRMI_regs *r)
  838.     {
  839.     unsigned int vret;
  840.     unsigned int seg, off;
  841.  
  842.     seg = get_int_seg(i);
  843.     off = get_int_off(i);
  844.  
  845.     /*
  846.      If the interrupt is in regular memory, it's probably
  847.      still pointing at a dos TSR (which is now gone).
  848.     */
  849.     if (seg < 0xa000 || (seg << 4) + off >= 0x100000)
  850.         {
  851.         fprintf(stderr, "Int 0x%x is not in rom (%04x:%04x)\n", i, seg, off);
  852.         return 0;
  853.         }
  854.  
  855.     memset(&context.vm.regs, 0, sizeof(context.vm.regs));
  856.  
  857.     set_regs(r);
  858.  
  859.     context.vm.regs.cs = seg;
  860.     context.vm.regs.eip = off;
  861.  
  862.     if (r->ss == 0 && r->sp == 0)
  863.         {
  864.         context.vm.regs.ss = context.stack_seg;
  865.         context.vm.regs.esp = context.stack_off;
  866.         }
  867.     else
  868.         {
  869.         context.vm.regs.ss = r->ss;
  870.         context.vm.regs.esp = r->sp;
  871.         }
  872.  
  873.     pushw(DEFAULT_VM86_FLAGS);
  874.     pushw(context.ret_seg);
  875.     pushw(context.ret_off);
  876.  
  877.     vret = run_vm86();
  878.  
  879.     get_regs(r);
  880.  
  881.     return vret;
  882.     }
  883.  
  884.